#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include "Connect.hpp"
#include "Log.hpp"

#define SEP " "                       // 请求正文中每个操作数之间的分隔符
#define SEP_LEN strlen(SEP)           // 请求正文中每个操作数之间的分隔符的长度
#define LINE_SEP "\r\n"               // 报头于报文的分隔符
#define LEN_LINE_SEP strlen(LINE_SEP) // 分隔符长度

using namespace std;

enum exitcode
{
    OK = 0,
    DIV_ZERO,
    MOD_ZERO,
    OP_ERROR
};

class request
{
public:
    // 构造
    request()
    {
    }

    // 析构
    ~request()
    {
    }

    // 将请求正文反序列化为请求对象
    bool deserialize(string &reqtext_str)
    {
        // 正文格式：x op y
        // 1、寻找第一个操作数与操作符之间的分隔符
        size_t pos = reqtext_str.find(SEP);
        if (pos == string::npos) // 不存在分隔符
            return false;

        // 存在第一个操作数
        string x_str = reqtext_str.substr(0, pos); // 第一个操作数
        _x = stoi(x_str);                          // 第一个操作数

        pos += SEP_LEN;                // pos定位至操作符位置
        if (pos >= reqtext_str.size()) // 不存在操作符
            return false;

        // 存在操作符
        _op = reqtext_str[pos];
        pos += (1 + SEP_LEN);          // pos定位至第二个操作数的起始位置
        if (pos >= reqtext_str.size()) // 不存在第二个操作数
            return false;

        string y_str = reqtext_str.substr(pos); // 第二个操作数(字符串形式)
        _y = stoi(y_str);

        return true;
    }

public:
    int _x;
    int _y;
    char _op;
};

class respond
{
public:
    // 构造
    respond()
    {
    }

    // 析构
    ~respond()
    {
    }

    // 将响应序列化成字符串形式的响应正文
    string serialize()
    {
        string resp_text;
        switch (_exitcode)
        {
        case (DIV_ZERO):
        {
            resp_text = "DIV_ZERO_ERR";
            break;
        }
        case (MOD_ZERO):
        {
            resp_text = "MOD_ZERO_ERR";
            break;
        }
        case (OP_ERROR):
        {
            resp_text = "OP_ERROR";
            break;
        }
        default:
        {
            // OK
            resp_text = to_string(_result);
            break;
        }
        }

        return resp_text;
    }

public:
    int _exitcode; // 退出码
    int _result;   // 计算结果
};

// 对请求中的数据进行计算，再将计算的结构结果以响应的形式返回
void calculate(const request &req, respond &resp)
{
    int x = req._x;
    int y = req._y;
    char op = req._op;

    switch (op)
    {
    case ('+'):
    {
        resp._exitcode = OK;
        resp._result = x + y;
        break;
    }
    case ('-'):
    {
        resp._exitcode = OK;
        resp._result = x - y;
        break;
    }
    case ('*'):
    {
        resp._exitcode = OK;
        resp._result = x * y;
        break;
    }
    case ('/'):
    {
        if (y == 0)
            resp._exitcode = DIV_ZERO;
        else
        {
            resp._exitcode = OK;
            resp._result = x / y;
        }
        break;
    }
    case ('%'):
    {
        if (y == 0)
            resp._exitcode = MOD_ZERO;
        else
        {
            resp._exitcode = OK;
            resp._result = x % y;
        }
        break;
    }
    default:
    {
        resp._exitcode = OP_ERROR;
        break;
    }
    }
}

// 给响应正文添加报头
string enlength(string &resp_text)
{
    int textlen = resp_text.size(); // 正文长度
    return to_string(textlen) + LINE_SEP + resp_text + LINE_SEP;
}

